package org.jvnc.rfb.state;

/**
* <br><br><center><table border="1" width="80%"><hr>
* <p>
* Copyright (C) 2006-2007 by Deon Wu
* <p>
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.0
* of the License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU Lesser General Public License</a>
* for more details.
* <p>
* You should have received a copy of the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">
* GNU Lesser General Public License</a> along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* <hr></table></center>
* **/

import gnu.rfb.rfb;

import java.io.DataInput;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import org.jvnc.logging.VLog;
import org.jvnc.rfb.RFBSocketClient;
import org.jvnc.rfb.event.*;
import org.jvnc.rfb.proto.*;
import org.jvnc.rfb.proto.client.FramebufferUpdateRequest;
import org.jvnc.rfb.proto.server.Bell;
import org.jvnc.rfb.proto.server.ColorMapEntries;
import org.jvnc.rfb.proto.server.CutText;
import org.jvnc.rfb.proto.server.FrameBufferUpdate;
import org.jvnc.rfb.proto.server.ServerStatus;

public class CommunicateRFB extends AbstractStateHandle {
	private static final VLog log = VLog.getLog(CommunicateRFB.class);
	
	//time in milliseconds between update request be sent.
	private long updatePeriod = 1000L * 3;	
	private CutText cutText = new CutText();
	private ColorMapEntries mapEntries = new ColorMapEntries();
	private FrameBufferUpdate bufferUpdate = new FrameBufferUpdate();
	private Bell bell = new Bell();
	private Timer timer = null;
	private boolean resetTimer = false;
	
	//保存当前服务器端的状态信息，在处理更新帧时，需要根据PixelFrmate得到帧的大小。
	private ServerStatus status = null;
	
	public CommunicateRFB(){
	}

	public RfbEvent process() throws IOException {
		DataInput in = socket.getInputStream();
		RfbEvent event = null;
		byte type = in.readByte();
		log.debug("Processing server to client message ! type = " + toString(type));
		
		switch (type) {
		case rfb.FrameBufferUpdate:
			bufferUpdate.setPixelFormate(status.getPixelFormate());
			bufferUpdate.readData(in);
			event = new BufferUpdateEvent(socket, bufferUpdate);
			break;
		case rfb.SetColourMapEntries:
			mapEntries.readData(in);
			event = new ColorMapEvent(socket, mapEntries);
			break;
		case rfb.Bell:
			bell.readData(in);
			event = new BellEvent(socket,bell);
			break;
		case rfb.ServerCutText:
			cutText.readData(in);
			event = new CutTextEvent(socket,cutText);
			break;
		default: 
			event = new ErrorEvent(socket, "Unkonw Server Message Type:" + type);
		}
		// socket.changeState(new CloseConnection());
		return event;
	}
	
	public boolean sendDataGram(final DataGram data, boolean isBlock) throws IOException{
		if(data instanceof FramebufferUpdateRequest){
			resetTimer = true;
			if(timer == null){
				//当第一次发送更新请求后才设置Timer。避免还在初始化参数时就开始更新。
				intiBufferUpdateTimer();
			}
		}
		if(isBlock){
			data.writeData(socket.getOutputStream());
		}else{
			//非阻塞方式时，创建一个新的线程用来发送信息。
			new Thread(){
				public void run(){
					try {
						data.writeData(socket.getOutputStream());
					} catch (IOException e) {
						log.error(e.toString(), e);
					}		
				}
			}.start();
		}
		return true;
	}
	//rfbClient.sendDataGram(new FramebufferUpdateRequest(x,y,width,height,isIncrement));
	
	
	public void setServerStatus(ServerStatus status){
		this.status = status;
	}
	public ServerStatus getServerStatus(){
		return this.status;
	}
	
	private void intiBufferUpdateTimer(){
		timer = new Timer(true);
		log.debug("intiBufferUpdateTimer.......");
		timer.schedule(new TimerTask(){
			FramebufferUpdateRequest dataGram = new FramebufferUpdateRequest(0,0,status.getFrameWidth(),status.getFrameHeight(),true);
			public void run() {
				if(!resetTimer){
					log.debug("Sending FrameBufferUpdateRequest.......");
					try {
						dataGram.writeData(socket.getOutputStream());
					} catch (IOException e) {
						e.printStackTrace();
					}
				}else{
					log.debug("The Timer is been reset!");
				}
				resetTimer = false;
			}}, 0, updatePeriod); 
	}
	
	private String toString(int type){
		String t = "";
		switch (type) {
		case rfb.FrameBufferUpdate:
			t = "FrameBufferUpdate";
			break;
		case rfb.SetColourMapEntries:
			t = "SetColourMapEntries";
			break;
		case rfb.Bell:
			t = "Bell";
			break;
		case rfb.ServerCutText:
			t = "ServerCutText";
			break;
		default:
			t = "Unknow";
		}
		return t + "(" + type + ")";
	}
	
}
